home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Risc World 3
/
Risc World 3.iso
/
SOFTWARE
/
ISSUE6
/
PD
/
PDF
/
pdf
/
c++
/
DrawOutputDevice
< prev
next >
Wrap
Text File
|
2003-02-23
|
28KB
|
1,009 lines
//--------------------------------------------------------------------------
//
// Copyright (c) 2002, Colin Granville
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or
// without modification, are permitted provided that the following
// conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// * The name Colin Granville may not be used to endorse or promote
// products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//--------------------------------------------------------------------------
#include "DrawOutputDevice.h"
#include "GuiDrawFileSprite.h"
#include "GuiDrawFileFonts.h"
#include "swis.h"
#include "ColourSpace.h"
#include "GfxState.h"
#include "iostream.h"
#include <math.h>
#include "guilib:gfx.h"
#include "GfxFont.h"
class Convert
{
public:
Convert(double* matrix) : ctm(matrix) {}
void userToDev(double x1, double y1, int& x2, int& y2)
{
x2 = (int)(ctm[0] * x1 + ctm[2] * y1 + ctm[4] + 0.5);
y2 = (int)(ctm[1] * x1 + ctm[3] * y1 + ctm[5] + 0.5);
}
private:
double* ctm;
};
//*****************************************************************
//*****************************************************************
//*****************************************************************
DrawOutputDevice::DrawOutputDevice()
: draw("PDF"),
path(draw),
text(draw),
noImages(0),
noText(0),
noType3Fonts(0),
noDrawings(0)
{
}
//*****************************************************************
DrawOutputDevice::~DrawOutputDevice() {}
//*****************************************************************
GBool DrawOutputDevice::upsideDown() {return gFalse;}
GBool DrawOutputDevice::useDrawChar() {return gTrue;}
GBool DrawOutputDevice::interpretType3Chars() {return !noType3Fonts;}
//*****************************************************************
void DrawOutputDevice::startPage(int /*pageNum*/, GfxState *state)
{
draw.reopen();
Convert cvt(state->getCTM());
cvt.userToDev(state->getX1(),state->getY1(),bounds.xmin,bounds.ymin);
cvt.userToDev(state->getX2(),state->getY2(),bounds.xmax,bounds.ymax);
clipbox.init(bounds);
if (font.getUsedFont(1))
{
GuiDrawFileFonts fonts(draw);
const char* fontname;
int index;
fonts.start();
for (index=1;fontname=font.getUsedFont(index),fontname;index++) fonts.add(index,fontname);
fonts.end();
}
}
//*****************************************************************
void DrawOutputDevice::endPage()
{
draw.endCurrentObject();
draw.setBBox(bounds);
font.clear();
}
//*****************************************************************
void DrawOutputDevice::saveState(GfxState*)
{
clipbox.push();
}
//*****************************************************************
void DrawOutputDevice::restoreState(GfxState* state)
{
clipbox.pop();
updateAll(state);
}
//*****************************************************************
void DrawOutputDevice::setClip(GfxState* state, int isEo)
{
// a bodge but its better than nothing
GfxPath& gfx_path=*state->getPath();
if (gfx_path.getNumSubpaths()==0) return;
int i;
int pathSize=0;
for (i=0;i<gfx_path.getNumSubpaths();i++)
{
GfxSubpath& subpath= *(gfx_path.getSubpath(i));
int number_of_points=subpath.getNumPoints();
if (number_of_points<2) continue;
int n;
pathSize+=3;
for (n=1;n<number_of_points;n++)
{
if (subpath.getCurve(n))
{
pathSize+=7; n+=2;
}
else
{
pathSize+=3;
}
}
if (subpath.isClosed()) pathSize++;
}
if (pathSize)
{
int* path=new int[pathSize+4];
if (!path) return;
int pos=0;
path[pos++]=pathSize+4;
path[pos++]=isEo;
int x,y;
Convert cvt(state->getCTM());
for (i=0;i<gfx_path.getNumSubpaths();i++)
{
GfxSubpath& subpath= *(gfx_path.getSubpath(i));
int number_of_points=subpath.getNumPoints();
if (number_of_points<2) continue;
path[pos++]=2;
cvt.userToDev(subpath.getX(0),subpath.getY(0),x,y);
path[pos++]=x; path[pos++]=y;
int n;
for (n=1;n<number_of_points;n++)
{
if (subpath.getCurve(n))
{
path[pos++]=6;
cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
path[pos++]=x; path[pos++]=y; n++;
cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
path[pos++]=x; path[pos++]=y; n++;
cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
path[pos++]=x; path[pos++]=y;
}
else
{
path[pos++]=8;
cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
path[pos++]=x; path[pos++]=y;
}
}
if (subpath.isClosed()) path[pos++]=5;
}
path[pos]=0;
clipbox.setPath(path);
}
}
//*****************************************************************
void DrawOutputDevice::clip(GfxState* state)
{
setClip(state,0);
}
//*****************************************************************
void DrawOutputDevice::eoClip(GfxState* state)
{
setClip(state,1);
}
//*****************************************************************
void DrawOutputDevice::updateLineJoin(GfxState* state)
{
pathState.setJoin(state->getLineJoin());
}
//*****************************************************************
void DrawOutputDevice::updateLineCap(GfxState* state)
{
pathState.setStartCap(state->getLineCap());
pathState.setEndCap(pathState.getStartCap());
}
//*****************************************************************
void DrawOutputDevice::updateLineWidth(GfxState* state)
{
pathState.setOutlineWidth((unsigned int)state->getTransformedLineWidth());
}
//*****************************************************************
inline unsigned int getColour(GfxRGB& rgb)
{
unsigned int r=(unsigned int)(rgb.r*256.0);
if (r>=255) r=255;
unsigned int g=(unsigned int)(rgb.g*256.0);
if (g>=255) g=255;
unsigned int b=(unsigned int)(rgb.b*256.0);
if (b>255) b=255;
return (r<<8) | (g<<16) | (b<<24);
}
//*****************************************************************
void DrawOutputDevice::updateFillColor(GfxState* state)
{
GfxRGB rgb;
state->getFillRGB(&rgb);
pathState.setFillColour(getColour(rgb));
}
//*****************************************************************
void DrawOutputDevice::updateStrokeColor(GfxState*state)
{
GfxRGB rgb;
state->getStrokeRGB(&rgb);
pathState.setOutlineColour(getColour(rgb));
}
//*****************************************************************
bool DrawOutputDevice::doPath(GfxState* state)
{
int i;
GfxPath& gfx_path=*state->getPath();
int mask;
Convert cvt(state->getCTM());
for (i=0;i<gfx_path.getNumSubpaths();i++)
{
GfxSubpath& subpath= *(gfx_path.getSubpath(i));
int number_of_points=subpath.getNumPoints();
if (number_of_points<2) continue;
path.moveTo();
int x,y;
cvt.userToDev(subpath.getX(0),subpath.getY(0),x,y);
mask=clipbox.clip(x,y);
path.point(x,y);
int n;
for (n=1;n<number_of_points;n++)
{
if (subpath.getCurve(n))
{
path.bezierTo();
cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
mask &= clipbox.clip(x,y);
path.point(x,y); n++;
cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
mask &= clipbox.clip(x,y);
path.point(x,y); n++;
cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
mask &= clipbox.clip(x,y);
path.point(x,y);
}
else
{
path.drawTo();
cvt.userToDev(subpath.getX(n),subpath.getY(n),x,y);
mask &= clipbox.clip(x,y);
path.point(x,y);
}
}
if (subpath.isClosed()) path.closeSubPath();
}
// removal of paths outside clipbox
// mask is nonzero if all points have an x or y clipped on the same side
return mask==0;
}
//*****************************************************************
//----- path painting
void DrawOutputDevice::stroke(GfxState* state)
{
if (noDrawings) return;
if (pathState.getOutlineColour() == GuiDrawFilePathState::OFF ||
!state->isPath()) return;
unsigned int fill_colour = pathState.getFillColour();
pathState.setFillColour(GuiDrawFilePathState::OFF);
path.start();
double* pattern;
int length;
double start;
state->getLineDash(&pattern,&length,&start);
pathState.setDashPattern(length);
if (length)
{
path.dashPattern((int)state->transformWidth(start),length);
for (;length;length--) path.dashElement((unsigned int)state->transformWidth(*pattern++));
}
if (doPath(state)) path.end(pathState); //if you don't end a path it's ignored
pathState.setDashPattern();
pathState.setFillColour(fill_colour);
}
//*****************************************************************
ostream& operator<<(ostream& out,const GuiBBox& box)
{
out << box.xmin << ' ' << box.ymin << ' ' << box.xmax << ' ' << box.ymax;
return out;
}
inline bool contains(const GuiBBox a,const GuiBBox& b)
{
return (b.xmin>=a.xmin && b.ymin>=a.ymin &&
b.xmax<=a.xmax && b.ymax<=a.ymax);
}
inline void clipTo(Clip& clipbox,int x,int y,int& ox, int& oy)
{
clipbox.clip(x,y);
ox=x;
oy=y;
}
bool DrawOutputDevice::doRectanglePath(GfxState* state)
{
if (!(clipbox.getPath() || clipbox.getBBox() )) return 0;
GfxPath *gfxpath=state->getPath();
if (gfxpath->getNumSubpaths()==1 &&
gfxpath->getSubpath(0)->getNumPoints() == 5)
{
GfxSubpath* subpath = gfxpath->getSubpath(0);
struct {int x,y; } pt[5];
Convert cvt(state->getCTM());
for (int i=0;i<5;i++)
{
cvt.userToDev(subpath->getX(i),subpath->getY(i),pt[i].x,pt[i].y);
}
GuiBBox box;
box.xmin=pt[0].x;
box.xmax=pt[2].x;
box.ymin=pt[0].y;
box.ymax=pt[2].y;
if (!( box.xmin==pt[4].x && box.ymin==pt[4].y &&
((box.xmin==pt[1].x && box.ymin == pt[3].y &&
box.xmax==pt[3].x && box.ymax == pt[1].y) ||
(box.xmin==pt[3].x && box.ymin == pt[1].y &&
box.xmax==pt[1].x && box.ymax == pt[3].y))
)) return 0;
if (box.xmin>box.xmax) {int temp=box.xmin;box.xmin=box.xmax;box.xmax=temp;}
if (box.ymin>box.ymax) {int temp=box.ymin;box.ymin=box.ymax;box.ymax=temp;}
if (!contains(box,*clipbox.getBBox()) )
{
if (!contains(*clipbox.getBBox(),box) ) return 0;
path.moveTo();
path.point(pt[0].x,pt[0].y);
path.drawTo();
path.point(pt[1].x,pt[1].y);
path.drawTo();
path.point(pt[2].x,pt[2].y);
path.drawTo();
path.point(pt[3].x,pt[3].y);
path.closeSubPath();
return 1;
}
int x,y;
for (const int* p=clipbox.getPath()+2;*p!=0;p++)
{
switch (*p)
{
case 2: path.moveTo();
clipTo(clipbox,p[1],p[2],x,y);
path.point(x,y);
p+=2;
break;
case 8: path.drawTo();
clipTo(clipbox,p[1],p[2],x,y);
path.point(x,y);
p+=2;
break;
case 5: path.closeSubPath();
break;
case 6: path.bezierTo();
clipTo(clipbox,p[1],p[2],x,y);
path.point(x,y);
clipTo(clipbox,p[3],p[4],x,y);
path.point(x,y);
clipTo(clipbox,p[5],p[6],x,y);
path.point(x,y);
p+=6;
break;
}
}
return 1;
}
return 0;
}
//*****************************************************************
void DrawOutputDevice::fill(GfxState* state)
{
if (noDrawings) return;
if (pathState.getFillColour() == GuiDrawFilePathState::OFF) return;
unsigned int outline_colour = pathState.getOutlineColour();
pathState.setOutlineColour(GuiDrawFilePathState::OFF);
pathState.setWindingRule(GuiDrawFilePathState::NON_ZERO);
path.start();
if (doRectanglePath(state) || doPath(state)) path.end(pathState);
pathState.setOutlineColour(outline_colour);
}
//*****************************************************************
void DrawOutputDevice::eoFill(GfxState* state)
{
if (noDrawings) return;
if (pathState.getFillColour() == GuiDrawFilePathState::OFF) return;
unsigned int outline_colour = pathState.getOutlineColour();
pathState.setOutlineColour(GuiDrawFilePathState::OFF);
pathState.setWindingRule(GuiDrawFilePathState::EVEN_ODD);
path.start();
if (doRectanglePath(state) || doPath(state)) path.end(pathState);
pathState.setOutlineColour(outline_colour);
}
//*****************************************************************
void DrawOutputDevice::updateFont(GfxState *state)
{
updateRender(state);
font.set(*state);
}
//*****************************************************************
void DrawOutputDevice::updateRender(GfxState *state)
{
}
//*****************************************************************
static Unicode* getLigature(Unicode u,int &len)
{
static Unicode ff[]= {'f','f'};
static Unicode ffi[]= {'f','f','i'};
static Unicode ffl[]= {'f','f','l'};
switch (u)
{
case 0xFB00: len=2;return ff;
case 0xFB03: len=3;return ffi;
case 0xFB04: len=3;return ffl;
}
return 0;
}
void DrawOutputDevice::drawChar(GfxState *state, double x, double y,
double dx, double dy,
double originX, double originY,
CharCode code, Unicode *uni, int uLen)
{
if (noText || uLen<=0) return;
if (state->getRender() & 1)
{
font.foreColour = pathState.getOutlineColour();
font.backColour = (font.foreColour==0xffffff00 ? 0 : 0xffffff00);
}
else
{
font.foreColour = pathState.getFillColour();
font.backColour = (font.foreColour==0xffffff00 ? 0 : 0xffffff00);
}
Unicode* u=uni;
unsigned int ch=font.getChar(u[0]);
if (!ch) u=getLigature(u[0],uLen);
if (u)
{
text.start();
double width=0;
int i;
for (i=0;i<uLen;i++)
{
ch=font.getChar(u[i]);
if (ch)
{
width+=font.getCharWidth(ch);
text.put(ch);
}
}
Convert cvt(state->getCTM());
cvt.userToDev(x,y,font.x,font.y);
font.setCharMatrix(originX,width);
text.end(font,font.getHandle());
}
}
//*****************************************************************
void DrawOutputDevice::drawString(GfxState *state, GString *s)
{
if (noText) return;
if (state->getRender() & 1)
{
font.foreColour = pathState.getOutlineColour();
font.backColour = (font.foreColour==0xffffff00 ? 0 : 0xffffff00);
}
else
{
font.foreColour = pathState.getFillColour();
font.backColour = (font.foreColour==0xffffff00 ? 0 : 0xffffff00);
}
GfxFont* fnt=state->getFont();
if (!fnt) return;
double x=0;
char* p=s->getCString();
int len= s->getLength();
Unicode uni[8];
int uLen;
CharCode code;
double xtotal=0;
double dummy;
int nChars=0;
int nSpaces=0;
double width=0;
Convert cvt(state->getCTM());
cvt.userToDev(state->getCurX(),state->getCurY(),font.x,font.y);
text.start();
while (len > 0)
{
Unicode* u=uni;
int n = fnt->getNextChar(p, len, &code,
u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
&x, &dummy, &dummy, &dummy);
unsigned int ch=font.getChar(u[0]);
if (!ch) u=getLigature(u[0],uLen);
if (u)
{
int i;
for (i=0;i<uLen;i++)
{
ch=font.getChar(u[i]);
if (ch)
{
text.put(ch);
width+=font.getCharWidth(ch);
}
}
}
xtotal+=x;
if (n == 1 && *p == ' ')
{
++nSpaces;
}
++nChars;
p += n;
len -= n;
}
if (nChars && state->getCharSpace()!=0)
xtotal+=nChars * state->getCharSpace()/state->getFontSize();
if (nSpaces && state->getWordSpace()!=0)
xtotal+=nSpaces * state->getWordSpace()/state->getFontSize();
font.setCharMatrix(xtotal,width);
text.end(font,font.getHandle());
}
//*****************************************************************
//scales draw units dpi to image dpi * (1<<16)
#define IMAGE_SCALE_FACTOR 128
class ReverseSamples
{
public:
ReverseSamples();
void setbpc(int bpc) {
if (bpc>4) b=b8;
else if (bpc>2) b=b4;
else if (bpc>1) b=b2;
else b=b1;
}
unsigned int sample(unsigned char c) {return b[c];}
private:
unsigned char b1[256];
unsigned char b2[256];
unsigned char b4[256];
unsigned char b8[256];
unsigned char* b;
};
ReverseSamples::ReverseSamples()
{
unsigned int i;
b=b8;
for (i=0;i<256;i++)
{
b1[i] = ((i & 1) << 7) |
((i & 2) << 5) |
((i & 4) << 3) |
((i & 8) << 1) |
((i & 16) >> 1) |
((i & 32) >> 3) |
((i & 64) >> 5) |
((i & 128) >> 7);
b2[i] = ((i & 3) << 6) |
((i & 0xc)<< 2) |
((i & 0x30) >> 2) |
((i & 0xC0) >> 6);
b4[i] = ((i & 0xf) << 4) |
((i & 0xf0) >> 4);
b8[i]=i;
}
}
ReverseSamples reverse;
//*****************************************************************
void DrawOutputDevice::drawImageMask(GfxState *state, Object* /*ref*/, Stream *str,
int width, int height, GBool invert,
GBool /*inlineImg*/)
{
if (width==0 || height==0 || noImages) return;
str->reset();
GuiDrawFileSprite sprite(draw);
sprite.start(width,height,1);
sprite.put(pathState.getFillColour());
sprite.put(pathState.getFillColour());
sprite.put(0);
sprite.put(0);
unsigned int bits=width-1;
int h,w;
sprite.startImage();
for (h=height;h;h--)
{
for (w=bits;w>=0;w-=32) sprite.put(0);
}
sprite.startMask();
reverse.setbpc(1);
unsigned int n;
// cerr << bits << ' ' << width << ' ' << height << endl;
unsigned int invertbits= (invert ? 0:-1u);
for (h=height;h;h--)
{
for (w=bits;w>=0;w-=32)
{
n=reverse.sample(str->getChar());
if (w>=8) n|=(reverse.sample(str->getChar()) << 8);
if (w>=16) n|=(reverse.sample(str->getChar()) << 16);
if (w>=24) n|=(reverse.sample(str->getChar()) << 24);
sprite.put(n^invertbits);
}
}
{ // calculate transform matrix and bounds
GuiBBox bounds;
double* mat=state->getCTM();
Convert cvt(mat);
GuiTransform matrix;
matrix.m0 = (int)( mat[0] * IMAGE_SCALE_FACTOR /width);
matrix.m1 = (int)( mat[1] * IMAGE_SCALE_FACTOR /width);
matrix.m2 = (int)( mat[2] * IMAGE_SCALE_FACTOR /height);
matrix.m3 = (int)( mat[3] * IMAGE_SCALE_FACTOR /height);
Boundary_start(bounds);
int x,y;
cvt.userToDev(0.0,0.0,x,y);
matrix.m4 = x;
matrix.m5 = y;
Boundary_point(bounds,x,y);
cvt.userToDev(0.0,1.0,x,y);
Boundary_point(bounds,x,y);
cvt.userToDev(1.0,1.0,x,y);
Boundary_point(bounds,x,y);
cvt.userToDev(1.0,0.0,x,y);
Boundary_point(bounds,x,y);
sprite.end(matrix,bounds);
}
}
//*****************************************************************
void DrawOutputDevice::drawImage(GfxState *state, Object * /*ref*/, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
int */*maskColors*/, GBool /*inlineImg*/)
{
if (width==0 || height==0 || noImages) return;
int bpc = colorMap->getBits();
int ncomps = colorMap->getNumPixelComps();
str->reset();
ColourSpace* colourSpace=makeColourSpace(colorMap->getColorSpace());
GuiDrawFileSprite sprite(draw);
// cerr << "mode " << colorMap->getColorSpace()->getMode() << endl;
// cerr << bpc << ' ' << ncomps << ' ' << width << ' ' << height << endl;
// cerr << "decode " << colorMap->getDecodeLow(0) << ' ' << colorMap->getDecodeHigh(0) << endl;
if (ncomps == 1 &&
(bpc<8 || (bpc==8 && width*height*3>2048) ) )
{
int step;
switch (bpc)
{
case 1: step=0xff;break;
case 2: step=0x55;break;
case 4: step=0x11;break;
case 8: step=1; break;
default: delete colourSpace;return; //illegal bpc
}
sprite.start(width,height,bpc);
if (draw.hasFailed())
{
delete colourSpace;
return;
}
if (colorMap->getColorSpace()->getMode()==csIndexed)
{
int col;
int i;
for (col=0,i=0;i<256;i+=step,col++)
{
unsigned int n=colourSpace->getRGB((unsigned char*)&col);
// cerr << n << endl;
sprite.put(n);
sprite.put(n);
}
}
else
{
unsigned int invert=(colorMap->getDecodeLow(0) > colorMap->getDecodeHigh(0) ? 0xffffff00 : 0);
int i;
for (i=0;i<256;i+=step)
{
unsigned int n=colourSpace->getRGB((unsigned char*)&i)^invert;
// cerr << n << endl;
sprite.put(n);
sprite.put(n);
}
}
sprite.startImage();
reverse.setbpc(bpc);
unsigned int bits=width*bpc-1;
int h,w;
unsigned int n;
for (h=height;h;h--)
{
for (w=bits;w>=0;w-=32)
{
n=reverse.sample(str->getChar());
if (w>=8) n|=(reverse.sample(str->getChar()) << 8);
if (w>=16) n|=(reverse.sample(str->getChar()) << 16);
if (w>=24) n|=(reverse.sample(str->getChar()) << 24);
sprite.put(n);
}
}
}
else if (bpc == 8)
{
sprite.start(width,height,32);
if (draw.hasFailed())
{
delete colourSpace;
return;
}
sprite.startImage();
unsigned char n[8];
int i;
int c;
int comps=ncomps;
if (comps>8) comps=8; //shouldn't happen but you never know
for (i=width*height;i;i--)
{
for (c=0;c<comps;c++) n[c] = str->getChar();
sprite.put(colourSpace->getRGB(n)>>8);
}
}
else
{
static unsigned char col1[] = {0,0xff};
static unsigned char col2[] = {0,0x55,0xaa,0xff};
static unsigned char col4[] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
unsigned char* colour;
sprite.start(width,height,32);
if (draw.hasFailed())
{
delete colourSpace;
return;
}
sprite.startImage();
int shift;
switch (bpc)
{
case 1: shift=1;colour=col1;break;
case 2: shift=2;colour=col2;break;
default: shift=4;colour=col4;break;
}
unsigned char n[8];
int c;
int comps=ncomps;
if (comps>8) comps=8; //shouldn't happen but you never know
int buffer;
int h,w;
for (h=height;h;h--)
{
buffer=0x1000000;
for (w=width;w;w--)
{
for (c=0;c<comps;c++)
{
if (buffer >= 0x1000000) { buffer=str->getChar(); buffer |= 0x10000;}
buffer <<=shift;
n[c]= colour[(buffer >> 8) & 0xf];
}
sprite.put(colourSpace->getRGB(n)>>8);
}
}
}
delete colourSpace;
{ // calculate transform matrix and bounds
GuiBBox bounds;
double* mat=state->getCTM();
Convert cvt(mat);
GuiTransform matrix;
matrix.m0 = (int)( mat[0] * IMAGE_SCALE_FACTOR /width);
matrix.m1 = (int)( mat[1] * IMAGE_SCALE_FACTOR /width);
matrix.m2 = (int)( mat[2] * IMAGE_SCALE_FACTOR /height);
matrix.m3 = (int)( mat[3] * IMAGE_SCALE_FACTOR /height);
Boundary_start(bounds);
int x,y;
cvt.userToDev(0.0,0.0,x,y);
matrix.m4 = x;
matrix.m5 = y;
Boundary_point(bounds,x,y);
cvt.userToDev(0.0,1.0,x,y);
Boundary_point(bounds,x,y);
cvt.userToDev(1.0,1.0,x,y);
Boundary_point(bounds,x,y);
cvt.userToDev(1.0,0.0,x,y);
Boundary_point(bounds,x,y);
if (clipbox.getPath()) sprite.startMaskFill();
sprite.end(matrix,bounds);
if (draw.hasFailed()) return;
//cerr << "SPRITE" << endl;
if (clipbox.getPath())
{
GuiTransform pathMatrix;
{
//extend stack so that sprite ptr doesn't move
char a[256];
//invert matrix
double m[4], om[4];
m[0]=((double)matrix.m0)/0x10000;
m[1]=((double)matrix.m1)/0x10000;
m[2]=((double)matrix.m2)/0x10000;
m[3]=((double)matrix.m3)/0x10000;
double det=1/(m[0]*m[3] - m[1]*m[2]);
//cerr << "m "<< m[0] <<',' << m[1] <<',' << m[2] <<',' << m[3] << endl;
om[0]=m[3]*det;
om[1]=-m[1]*det;
om[2]=-m[2]*det;
om[3]=m[0]*det;
//cerr << "om "<< om[0] <<',' << om[1] <<',' << om[2] <<',' << om[3] << endl;
pathMatrix.m0=(int)(om[0]*0x10000);
pathMatrix.m1=(int)(om[1]*0x10000);
pathMatrix.m2=(int)(om[2]*0x10000);
pathMatrix.m3=(int)(om[3]*0x10000);
pathMatrix.m4=(int)((m[2]*(double)matrix.m5-m[3]*(double)matrix.m4)*det);
pathMatrix.m5=(int)((m[1]*(double)matrix.m4-m[0]*(double)matrix.m5)*det);
}
int r1,r2,r3;
char* spr=sprite.getPtr();
_kernel_oserror* err=_swix(OS_SpriteOp,_INR(0,3) | _OUTR(1,3),0x200+61,spr,spr,0,&r1,&r2,&r3);
if (err==0)
{
_swix(ColourTrans_SetColour,_IN(0)|_INR(3,4),0xff,0,0);
err=_swix(Draw_Fill,_INR(0,3),clipbox.getPath()+2,0,&pathMatrix,0);
_swix(OS_SpriteOp,_INR(0,3),0x200+61,r1,r2,r3);
}
// cerr << matrix.m0 << ' ' << matrix.m1 << endl;
// cerr << matrix.m2 << ' ' << matrix.m3 << endl;
// cerr << matrix.m4 << ' ' << matrix.m5 << endl;
// cerr <<"xy " << matrix.m4/256 <<',' << matrix.m5/256 << endl;
// int* p=clipbox.getPath();
// int i;
// cerr << "++++++++" << endl;
// for (i=0;i<p[0]-1;i++)
// {
// cerr << p[i];
// switch (p[i])
// {
// case 6: cerr << ' '
// << p[i+1] << ',' << p[i+2] << ' '
// << p[i+3] << ',' << p[i+5] << ' '
// << p[i+5] << ',' << p[i+6];
// i+=6;
// break;
// case 2:
// case 8: cerr << ' '
// << p[i+1]/256 << ',' << p[i+2]/256;
// i+=2;
// break;
// }
// cerr << endl;
// }
// cerr << "--------" << endl;
}
}
}